#include "CustomBoxView.h"

#include <QEvent>
#include <QMutexLocker>
#include <QPainter>
#include <QPushButton>
#include <QResizeEvent>
#include <QScrollArea>
#include <QScrollBar>

#define DEFAULT_MAX_BOX_CNT 300
#define DEFAULT_CELL_HEIGHT 50
#define DEFAULT_CELL_WIDHT 80
#define DEFAULT_SPACING 5

CCustomBoxCell::CCustomBoxCell(QWidget* parent) :
    QPushButton(parent)
{
}

CCustomBoxCell::~CCustomBoxCell()
{
}

void CCustomBoxCell::paintEvent(QPaintEvent* e)
{
    QRect rect = this->rect();

    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing);
    p.setRenderHint(QPainter::SmoothPixmapTransform);
    p.fillRect(rect, QColor("#00AA00"));

    // door status
    if (data_[EDataRole_Door].toChar() != 0x00)
    {
        p.fillRect(
            QRect(DEFAULT_CELL_WIDHT - 20, 10, 10, DEFAULT_CELL_HEIGHT - 20),
            QColor("#000000"));
    }

    // item status
    if (data_[EDataRole_Item].toChar() != 0x00)
    {
        QPainterPath path;
        path.addEllipse(QPoint(DEFAULT_CELL_WIDHT / 2, DEFAULT_CELL_HEIGHT / 2), 15, 15);
        p.fillPath(path, QColor("#000000"));
    }

    if (this->isChecked())
    {
        QPainterPath p1, p2;
        p1.addRect(0, 0, DEFAULT_CELL_WIDHT, DEFAULT_CELL_HEIGHT);
        p2.addRect(3, 3, DEFAULT_CELL_WIDHT - 6, DEFAULT_CELL_HEIGHT - 6);
        p.fillPath(p1 - p2, QColor("#000000"));
    }

    // draw box no
    p.save();
    QFont font;
    font.setPointSize(16);
    p.setFont(font);
    p.setPen(QColor("#FFFFFF"));
    p.drawText(rect, Qt::AlignCenter, data_[EDataRole_Index].toString());
    p.restore();
}

///////////////////////////////////////////////////////
CCustomBoxView::CCustomBoxView(QWidget* parent) :
    QWidget(parent), btn_group_(new QButtonGroup(this))
{
    init();
    setMouseTracking(true);
    // connect
    connect(btn_group_, SIGNAL(buttonClicked(int)), this, SIGNAL(boxClicked(int)));
}

CCustomBoxView::~CCustomBoxView()
{
}

void CCustomBoxView::SetLayout(int max_row, int max_col)
{
    hide_all();
    if (max_row * max_col > DEFAULT_MAX_BOX_CNT)
    {
        return;
    }

    setFixedWidth(max_col * (DEFAULT_CELL_WIDHT + DEFAULT_SPACING));
    setFixedHeight(max_row * (DEFAULT_CELL_HEIGHT + DEFAULT_SPACING));

    int index = 0;
    for (size_t col = 0; col < max_col; ++col)
    {
        for (size_t row = 0; row < max_row; ++row)
        {
            auto cell = cells_[index];
            int y = row * (DEFAULT_CELL_HEIGHT + DEFAULT_SPACING);
            int x = col * (DEFAULT_CELL_WIDHT + DEFAULT_SPACING);
            cell->move(x, y);
            cell->show();
            cell->SetData(CCustomBoxCell::EDataRole_Index, index + 1);
            index++;
        }
    }
}

void CCustomBoxView::SetData(int index, int role, QVariant data)
{
    cells_[index]->SetData(role, data);
}

void CCustomBoxView::init()
{
    btn_group_->setExclusive(true);
    for (int i = 0; i < DEFAULT_MAX_BOX_CNT; ++i)
    {
        auto cell = new CCustomBoxCell(this);
        cell->setCheckable(true);
        cell->setFixedSize(DEFAULT_CELL_WIDHT, DEFAULT_CELL_HEIGHT);
        cell->setMouseTracking(true);
        cell->installEventFilter(this);
        cell->hide();
        btn_group_->addButton(cell, i + 1);
        cells_.push_back(cell);
    }
}

void CCustomBoxView::hide_all()
{
    std::for_each(cells_.begin(), cells_.end(), [&](CCustomBoxCell* c) {
        c->hide();
        c->setChecked(false);
    });
}

void CCustomBoxView::resize_btngroup(int32_t size)
{
    if ((size_t)size < cells_.size())
    {
        return;
    }

    for (int i = cells_.size(); i < size; ++i)
    {
        auto cell = new CCustomBoxCell(this);
        cell->setCheckable(true);
        cell->setFixedSize(DEFAULT_CELL_WIDHT, DEFAULT_CELL_HEIGHT);
        cell->hide();
        cells_.push_back(cell);
        btn_group_->addButton(cell, i + 1);
    }
}

bool CCustomBoxView::eventFilter(QObject* watched, QEvent* event)
{
    if (qobject_cast<CCustomBoxCell*>(watched) != Q_NULLPTR)
    {
        QWidget::eventFilter(watched, event);
        if (event->type() == QEvent::MouseButtonPress)
        {
            flag_drag_ = true;
            flag_drag_continue_ = false;
            QMouseEvent* e = (QMouseEvent*)event;
            drag_posx_ = e->globalPos().x();
            drag_posy_ = e->globalPos().y();
        }
        else if (event->type() == QEvent::MouseButtonRelease)
        {
            flag_drag_ = false;
        }
        else if (event->type() == QEvent::MouseMove)
        {
            QMouseEvent* e = (QMouseEvent*)event;
            QScrollArea* wa = qobject_cast<QScrollArea*>(this->parent()->parent());
            if (wa == Q_NULLPTR || e == Q_NULLPTR || !flag_drag_)
            {
                return true;
            }

            QScrollBar* barx = wa->horizontalScrollBar();
            QScrollBar* bary = wa->verticalScrollBar();
            QPoint p = e->globalPos();
            int offsetx = p.x() - drag_posx_;
            int offsety = p.y() - drag_posy_;
            if (!flag_drag_continue_ && qAbs(offsetx) < 10 && qAbs(offsety) < 10)
            {
                return true;
            }

            flag_drag_continue_ = true;
            drag_posx_ = p.x();
            drag_posy_ = p.y();
            if (barx != Q_NULLPTR)
            {
                barx->setValue(barx->value() - offsetx);
            }
            if (bary != Q_NULLPTR)
            {
                bary->setValue(bary->value() - offsety);
            }
        }
    }

    return QWidget::eventFilter(watched, event);
}

void CCustomBoxView::mousePressEvent(QMouseEvent* e)
{
    flag_drag_ = true;
    flag_drag_continue_ = false;
    drag_posx_ = e->globalPos().x();
    drag_posy_ = e->globalPos().y();
    return QWidget::mousePressEvent(e);
}

void CCustomBoxView::mouseMoveEvent(QMouseEvent* e)
{
    if (!flag_drag_)
    {
        return;
    }

    QScrollArea* wa = qobject_cast<QScrollArea*>(this->parent()->parent());
    if (wa == Q_NULLPTR)
    {
        return QWidget::mouseMoveEvent(e);
    }

    QScrollBar* barx = wa->horizontalScrollBar();
    QScrollBar* bary = wa->verticalScrollBar();
    QPoint p = e->globalPos();
    int offsetx = p.x() - drag_posx_;
    int offsety = p.y() - drag_posy_;
    if (!flag_drag_continue_ && qAbs(offsetx) < 10 && qAbs(offsety) < 10)
    {
        return;
    }

    flag_drag_continue_ = true;
    drag_posx_ = p.x();
    drag_posy_ = p.y();
    if (barx != Q_NULLPTR)
    {
        barx->setValue(barx->value() - offsetx);
    }
    if (bary != Q_NULLPTR)
    {
        bary->setValue(bary->value() - offsety);
    }
}

void CCustomBoxView::mouseReleaseEvent(QMouseEvent* e)
{
    flag_drag_ = false;
    return QWidget::mouseReleaseEvent(e);
}
